﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace AddIn.EA.Framework.Common
{
    /// <summary>
    /// Abstract class that is used as based class for the entire elements of the framework.
    /// </summary>
    /// <remarks>This base class encapsulate actions and features common for all object of EA Object Model, except collections.</remarks>
    /// <typeparam name="TReference">Reference type of EA Object Model.</typeparam>
    public abstract class BaseElement<TReference> : IElement
    {
        #region Constructors
        /// <summary>
        /// Constructor that initialize some properties.
        /// </summary>
        /// <param name="reference">Reference with the same reference type related to generic parameter of the class.</param>
        /// <param name="parent">The parent element.</param>
        public BaseElement(TReference reference, IElement parent)
        {
            this.Reference = reference;
            this.Parent = parent;
        }
        #endregion

        #region Properties
        /// <summary>
        /// EA reference type
        /// </summary>
        protected TReference Reference { get; set; }
        /// <summary>
        /// The parent element
        /// </summary>
        public IElement Parent { get; private set; }
        /// <summary>
        /// The id of referenced type.
        /// </summary>
        public abstract int ID { get; }
        /// <summary>
        /// The name of referenced typed.
        /// </summary>
        public abstract string Name { get; set; }
        #endregion

        #region Public Methods
        /// <summary>
        /// Update the database of EA and all user interfaces objects visible in EA.
        /// </summary>
        public virtual void Update()
        {
            if (typeof(TReference).GetInterfaces().Length > 0)
            {
                MethodInfo method = typeof(TReference).GetInterfaces()[0].GetMethod("Update");

                if (method != null)
                {
                    bool updated = (bool)method.Invoke(this.Reference, new object[0]);

                    if (!updated)
                        throw new InvalidOperationException(GetLastError());
                }
            }
        }
        /// <summary>
        /// Get a last error occurred during the updating data in Update Method.
        /// </summary>
        /// <returns>Description errors was occurred</returns>
        public virtual string GetLastError()
        {
            string result = string.Empty;

            if (typeof(TReference).GetInterfaces().Length > 0)
            {
                MethodInfo method = typeof(TReference).GetInterfaces()[0].GetMethod("GetLastError");

                if (method != null)
                {
                    try
                    {
                        result = (string)method.Invoke(this.Reference, new object[0]);
                    }
                    catch
                    {
                        result = string.Empty;
                    }
                }
            }

            return result;
        }
        #endregion
        
    }
}
